<!-- 拖拽容器
    1.支持缩放、移动
    2.依赖DraBox的位置信息，left、top以DraBox为基准（重要）

  外部配置；
    ooption: 样式
    hasWall: 是否有边界（对移动有用）
    isActive：是否时激活状态

  对外事件：
    1.创建事件（激活时）：active
    2.移动结束时：move
    3.缩放结束时：resize
-->
<template>
  <div @mousedown.stop="createMoveEvent($event,'move')" :style="itemStyle" class="mdragble-item" dragtype="item"
       :item_index="index">
    <!-- 移动按钮 -->
    <div>
      <slot name="move"></slot>
    </div>
    <!-- 显示内容 -->
    <slot name="default"></slot>
    <!--缩放按钮-->
    <!-- 45度角缩放 -->
    <div @mousedown.stop="createMoveEvent($event,'resize_lt')" ref="bar" class="mdragble-resise-bar--lt"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_lb')" ref="bar" class="mdragble-resise-bar--lb"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_rt')" ref="bar" class="mdragble-resise-bar--rt"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_rb')" ref="bar" class="mdragble-resise-bar--rb"
         :item_index="index"></div>
    <!-- 横纵缩放 -->
    <div @mousedown.stop="createMoveEvent($event,'resize_l')" ref="bar" class="mdragble-resise-bar--left"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_t')" ref="bar" class="mdragble-resise-bar--top"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_r')" ref="bar" class="mdragble-resise-bar--right"
         :item_index="index"></div>
    <div @mousedown.stop="createMoveEvent($event,'resize_b')" ref="bar" class="mdragble-resise-bar--bottom"
         :item_index="index"></div>

  </div>
</template>

<script>
  export default {
    name: "DragItem",
    props: {
      // 分组名称，用于跨组件寻找父级
      groupName: {
        type: String,
        default: 'DragBox'
      },
      // 样式
      option: {
        type: Object,
        default: {
          zIndex: 1,
          width: 100,
          height: 100,
          left: 100,
          top: 100,
          minHeight: 30,
          minWidth: 30,
        }
      },
      // 是否有边界（对移动有效）
      hasWall: {
        type: Boolean,
        default: false
      },
      isActive: {
        type: Boolean,
        default: false
      },
    },
    data() {
      return {
        eventType: '',
        // top、left最大、最小值，在移动鼠标时赋值，用于处理最终边界判断
        minX: 0,
        minY: 0,
        maxX: 0,
        maxY: 0,
        // 容器最大尺寸
        maxWidth: 0,
        maxHeight: 0,
        // 点击时做记录（暂时没用上）
        beginX: 0,
        beginY: 0,
        // 上一次鼠标停留位置（用于计算步长）
        lastX: 0,
        lastY: 0,
      };
    },
    methods: {
      /** 模块事件管理 */
      // 创建移动鼠标事件
      createMoveEvent({pageX, pageY}, evenType) {
        // 1.初始化信息
        this.readyOption();
        // 2.记录当前位置
        const point = this.checkXYOffset({
          x: pageX, y: pageY
        });
        this.beginX = point.x;
        this.beginY = point.y;
        // 3.发送事件
        // this.$emit('onBegin', point);
        // 4.更新坐标
        this.lastX = this.beginX;
        this.lastY = this.beginY;
        // 5.注册事件
        this.eventType = evenType;
        if (evenType === 'move') { // 移动容器
          window.addEventListener('mousemove', this.moveEvent);
          window.addEventListener('mouseup', this.cleanEvent);
        } else { // 缩放容器
          window.addEventListener('mousemove', this.moveEvent);
          window.addEventListener('mouseup', this.cleanEvent);
        }
        this.$emit('active', '没想好传啥');
      },
      // 鼠标移动时回调
      moveEvent({pageX, pageY}) {
        // 1.计算相对父组件坐标
        const point = this.checkXYOffset({
          x: pageX, y: pageY
        });

        // 2.计算移动后位置
        if (!isNaN(point.x)) {
          const diffX = point.x - this.lastX;
          const diffY = point.y - this.lastY;
          let newOffsetDiff;

          this.minX = this.minY = 0;
          this.maxX = this.maxWidth;
          this.maxY = this.maxHeight;
          // 更新容器
          switch (this.eventType) {
            case 'move':
              this.maxX = this.maxWidth - this.option.width;
              this.maxY = this.maxHeight - this.option.height;
              this.setOffset({
                diffX,
                diffY
              }, this.hasWall);
              break;
            case 'resize_lt':
              this.maxX = this.maxWidth - (this.maxWidth - this.option.left - this.option.width + this.option.minWidth);
              this.maxY = this.maxHeight - (this.maxHeight - this.option.top - this.option.height + this.option.minHeight);
              newOffsetDiff = this.setOffset({
                diffX,
                diffY
              });
              newOffsetDiff.diffX = -newOffsetDiff.diffX;
              newOffsetDiff.diffY = -newOffsetDiff.diffY;
              break;
            case 'resize_lb':
              this.maxX = this.maxWidth - (this.maxWidth - this.option.left - this.option.width + this.option.minWidth);
              newOffsetDiff = this.setOffset({
                diffX
              });
              newOffsetDiff.diffX = -newOffsetDiff.diffX;
              newOffsetDiff.diffY = diffY;
              break;
            case 'resize_rt':
              this.maxY = this.maxHeight - (this.maxHeight - this.option.top - this.option.height + this.option.minHeight);
              newOffsetDiff = this.setOffset({
                diffY
              });
              newOffsetDiff.diffY = -newOffsetDiff.diffY;
              newOffsetDiff.diffX = diffX;
              break;
            case 'resize_rb':
              this.minX = this.option.left;
              newOffsetDiff = {
                diffX,
                diffY
              };
              break;
            case 'resize_t':
              this.maxY = this.maxHeight - (this.maxHeight - this.option.top - this.option.height + this.option.minHeight);
              newOffsetDiff = this.setOffset({
                diffY
              });
              newOffsetDiff.diffY = -newOffsetDiff.diffY;
              break;
            case 'resize_b':
              newOffsetDiff = {
                diffY,
              };
              break;
            case 'resize_l':
              this.maxX = this.maxWidth - (this.maxWidth - this.option.left - this.option.width + this.option.minWidth);
              newOffsetDiff = this.setOffset({
                diffX,
              });
              newOffsetDiff.diffX = -newOffsetDiff.diffX;
              break;
            case 'resize_r':
              newOffsetDiff = {
                diffX,
              };
              break;
          }
          // 更新容器大小
          if (this.eventType !== 'move') {
            this.setSize({
              diffWidth: newOffsetDiff.diffX,
              diffHeight: newOffsetDiff.diffY,
            });
            //调整后信息传给回调函数
            this.$emit('resize', '没想好传啥');
          } else {
            //调整后信息传给回调函数
            this.$emit('move', '没想好传啥')
          }
        }
        // 3.更新坐标
        this.lastX = point.x;
        this.lastY = point.y;
      },
      // 清除事件
      cleanEvent() {
        window.removeEventListener('mousemove', this.moveEvent);
        window.removeEventListener('mouseup', this.cleanEvent);
      },
      /** 坐标操作 */
      // 设置位置,返回实际变更的坐标步数
      setOffset({diffX, diffY}, hasWall = true) {
        const r = {
          diffX: 0, diffY: 0
        };
        const oldLeft = this.option.left;
        const oldTop = this.option.top;
        if (diffX) {
          this.option.left += diffX;
          if (hasWall) {
            this.option.left = this.getNumberFromSection(this.option.left, this.minX, this.maxX);
          }
          r.diffX = this.option.left - oldLeft;
        }
        if (diffY) {
          this.option.top += diffY;
          if (hasWall) {
            this.option.top = this.getNumberFromSection(this.option.top, this.minY, this.maxY);
          }
          r.diffY = this.option.top - oldTop;
        }
        return r;
      },
      // 设置大小，返回实际变更步数
      setSize({diffWidth, diffHeight}) {
        const r = {
          diffWidth: 0, diffHeight: 0
        };
        const oldWidth = this.option.width;
        const oldHeight = this.option.height;
        if (diffWidth) {
          this.option.width += diffWidth;
          this.option.width = this.getNumberFromSection(this.option.width, this.option.minWidth, this.maxWidth);
          r.diffWidth = this.option.left - oldWidth;
        }
        if (diffHeight) {
          this.option.height += diffHeight;
          this.option.height = this.getNumberFromSection(this.option.height, this.option.minHeight, this.maxHeight);
          r.diffHeight = this.option.height - oldHeight;
        }
        return r;
      },
      /** 工具 */
      // 计算并记录坐标
      readyOption() {
        const parent = this.dispatch(this.groupName);
        if (parent) {
          const {top, left, width, height} = parent.getDomInfo();
          this.maxWidth = width || 0;
          this.maxHeight = height || 0;
          this.diffX = Math.round(left);
          this.diffY = Math.round(top);
        }
      },
      // 向上按groupName寻找组件
      dispatch(groupName = this.groupName) {
        var parent = this.$parent || this.$root;
        var name = parent.groupName;

        while (parent && (!name || name !== groupName)) {
          parent = parent.$parent;

          if (parent) {
            name = parent.groupName;
          }
        }
        return parent;
      },
      // 数值边界矫正
      getNumberFromSection(val, min, max) {
        val = Math.max(min, val);
        val = Math.min(val, max);
        return val;
      },
      // 矫正操作坐标
      checkXYOffset({x, y}) {
        x -= this.diffX;
        y -= this.diffY;
        x = Math.max(0, x);
        x = Math.min(x, this.maxWidth);
        y = Math.max(0, y);
        y = Math.min(y, this.maxHeight);
        return isNaN(x) || isNaN(y) ? null : {x, y};
      },
    },
    computed: {
      itemStyle() {
        let {
          width = 100,
          height = 100,
          left = 0,
          top = 0,
          zIndex = 1,
          backGround = '',
          border
        } = this.option;

        let style = {
          width: `${width}px`,
          height: `${height}px`,
          left: `${left}px`,
          top: `${top}px`,
          zIndex,
          backGround,
          border: this.isActive ? border : '',
        };
        return style;
      }

    }
  }
</script>

<style scoped lang="postcss">

  .mdragble-item {
    position: absolute;
    cursor: move;
  }

  /* 缩放按钮 8个 */
  .mdragble-resise-bar--lt,
  .mdragble-resise-bar--rt,
  .mdragble-resise-bar--lb,
  .mdragble-resise-bar--rb {
    position: absolute;
    z-index: 1;
    width: 0;
    height: 0;
    border-right: 4px solid #00000000;
    border-bottom: 4px solid #00000000;
  }

  .mdragble-resise-bar--lt {
    left: -1px;
    top: -1px;
    cursor: se-resize;
  }

  .mdragble-resise-bar--lb {
    left: -1px;
    bottom: -1px;
    cursor: sw-resize;
  }

  .mdragble-resise-bar--rt {
    right: -1px;
    top: -1px;
    cursor: sw-resize;
  }

  .mdragble-resise-bar--rb {
    right: -1px;
    bottom: -1px;
    cursor: se-resize;
  }

  .mdragble-resise-bar--left {
    position: absolute;
    width: 1px;
    height: 100%;
    left: 0;
    cursor: col-resize;
  }

  .mdragble-resise-bar--top {
    position: absolute;
    width: 100%;
    height: 1px;
    top: 0;
    cursor: row-resize;
  }

  .mdragble-resise-bar--right {
    position: absolute;
    width: 1px;
    height: 100%;
    right: 0;
    cursor: col-resize;
  }

  .mdragble-resise-bar--bottom {
    position: absolute;
    width: 100%;
    height: 1px;
    bottom: 0;
    cursor: row-resize;
  }
</style>
